package com.netkiller.mailmonitor.workflow.impl.processor;


import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.netkiller.mailmonitor.core.AppException;
import com.netkiller.mailmonitor.workflow.AbstractWorkflowProcessor;
import com.netkiller.mailmonitor.workflow.AbstractWorkflowTask;
import com.netkiller.mailmonitor.workflow.WorkflowContext;
import com.netkiller.mailmonitor.workflow.WorkflowExecutionException;
import com.netkiller.mailmonitor.workflow.WorkflowInfo;
import com.netkiller.mailmonitor.workflow.WorkflowTask;
import com.netkiller.mailmonitor.workflow.entity.Workflow;
import com.netkiller.mailmonitor.workflow.service.WorkflowService;

/**
 * A workflow processor implementation that executes WorkflowTasks in sequence.
 * 
 * @author prateek
 * 
 */
@Component
public class WorkflowSequenceProcessor extends AbstractWorkflowProcessor {

	@Autowired
	private WorkflowService workflowService;
	
	protected final Logger log = Logger.getLogger(getClass().getName());

	public WorkflowSequenceProcessor(WorkflowContext context) {
		super(context);
	}

	public WorkflowSequenceProcessor() {
		super();
	}


	
	public void doTasks() {
		WorkflowContext currentContext = context;
		WorkflowInfo currentInfo = context.getWorkflowInfo();
		Workflow workflow = null;		
		try {
		//	System.out.println("running : " + currentInfo.getWorkflowInstance());	
			workflow = workflowService.getByWorkflowInstanceId(currentInfo.getWorkflowInstance());
		} catch (AppException e2) {
			log.log(Level.SEVERE,"Cannot Convert from Bolb to WorkflowContext : " + e2.getMessage());
			System.out.println("e1 : " + e2.getMessage());
		}
		Boolean isSuccessful = true;
		Boolean isNewWorkflow = currentInfo.getIsNewWorkflow();
		int startingIndex = getStartingTaskIndex();
		currentInfo.setIsNewWorkflow(false);
		for (int loopIndex = startingIndex; loopIndex < workflowTasks.size(); loopIndex++) {
			WorkflowTask currentTask = (WorkflowTask) workflowTasks.get(loopIndex);
			try {
				//System.out.println("running tasks : " + currentTask.getTaskName());
				currentContext = currentTask.execute(currentContext);
			} catch (WorkflowExecutionException e) {
				System.out.println("e2 : " + e.getMessage());
				try { 
					currentTask.retry(currentContext, e);
				} catch (WorkflowExecutionException e1) {
					log.log(Level.SEVERE,"Retry Count Exceeded for Workflow" + currentInfo.getWorkflowInstance());
					currentInfo.setLastFailedTaskName(currentTask.getTaskName());
					currentContext.setWorkflowInfo(currentInfo);
					isSuccessful = false;
					break;
				}
			}
		}
		try {
			saveWorkflowInstance(workflow, currentContext, isNewWorkflow, isSuccessful);
		} catch (AppException e) {
			log.log(Level.SEVERE,"falied to update Workflow in DataStore " + workflow, e);
			
		}
	}

	private void saveWorkflowInstance(Workflow workflow, WorkflowContext currentContext, boolean createNew,
			boolean isSuccessful) throws AppException {
		if (isSuccessful) {
			workflow.setWorkflowStatus(WorkflowStatusType.SUCCESSFUL.toString());
			currentContext.getWorkflowInfo().setLastFailedTaskName(null);
		} else {
			workflow.setWorkflowStatus(WorkflowStatusType.FAILED.toString());
		}
		//workflow.setWorkflowName(currentContext.getWorkflowInfo().getWorkflowName()); workflow name already exists on workflow
		workflow.setWorkflowInstanceId(currentContext.getWorkflowInfo().getWorkflowInstance());
		workflow.setContext(currentContext);
		if (createNew) {
			try {
				workflowService.createWorkflow(workflow);
			} catch (AppException e) {
				log.log(Level.INFO,"falied to create Workflow in DataStore", e);
			}
		} else {
			try {
				workflowService.updateWorkflow(workflow);
			} catch (AppException exception) {
				log.log(Level.SEVERE,"falied to update Workflow in DataStore " + workflow, exception);
			}
		}
	}

	private int getStartingTaskIndex() {
		WorkflowInfo currentInfo = context.getWorkflowInfo();
		int startingIndex = 0;
		if (currentInfo.getIsNewWorkflow()) {
			return startingIndex;
		} else {
			for (Iterator<WorkflowTask> taskIterator = workflowTasks.iterator(); taskIterator.hasNext();) {
				AbstractWorkflowTask currentTask = (AbstractWorkflowTask) taskIterator.next();
				if (currentTask.getTaskName().equals(currentInfo.getLastFailedTaskName())) {
					break;
				}
				startingIndex++;
			}
			return startingIndex;
		}
	}

}